Source code for hysop.tools.numpywrappers

# Copyright (c) HySoP 2011-2024
#
# This file is part of HySoP software.
# See "https://particle_methods.gricad-pages.univ-grenoble-alpes.fr/hysop-doc/"
# for further info.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


"""
Interface to numpy arrays, with hysop predifined types for int, real ...

Those functions are useful to enforce hysop predefined types in numpy arrays.
"""

from hysop.tools.htypes import check_instance
import numpy as npw

##########################
### EXTRA HYSOP METHODS ##


def __generate_hysop_type_functions():

    functions = {
        "as{type}array": '''
def hysop_array_generated_method(a, order=HYSOP_ORDER, **kargs):
    """
    Convert the input to an array of dtype HYSOP_{TYPE}.
    """
    dtype = HYSOP_{TYPE}
    return np.asarray(a=a, dtype=dtype, order=order, **kargs)
''',
        "asany{type}array": '''
def hysop_array_generated_method(a, order=HYSOP_ORDER, **kargs):
    """
    Convert the input to an array of dtype HYSOP_{TYPE}.
    """
    dtype = HYSOP_{TYPE}
    return np.asanyarray(a=a, dtype=dtype, order=order, **kargs)
''',
        "{type}_prod": '''
def hysop_array_generated_method(a, axis=None, out=None, **kargs):
    """
    Sum of array elements over a given axis.
    """
    dtype = HYSOP_{TYPE}
    return np.prod(a=a,axis=axis,out=out,dtype=dtype,**kargs)
''',
        "{type}_sum": '''
def hysop_array_generated_method(a, axis=None, out=None, **kargs):
    """
    Sum of array elements over a given axis.
    """
    dtype = HYSOP_{TYPE}
    return np.sum(a=a,axis=axis,out=out,dtype=dtype,**kargs)
''',
        "{type}_empty": '''
def hysop_array_generated_method(shape, order=HYSOP_ORDER, **kargs):
    """
    Return a new array of given shape and type, without initializing entries.
    """
    dtype = HYSOP_{TYPE}
    return np.empty(shape=shape, dtype=dtype, order=order, **kargs)
''',
        "{type}_ones": '''
def hysop_array_generated_method(shape, order=HYSOP_ORDER, **kargs):
    """
    Return a new array of given shape filled with ones of type HYSOP_{TYPE}.
    """
    dtype = HYSOP_{TYPE}
    return np.ones(shape=shape, order=order, dtype=dtype, **kargs)
''',
        "{type}_zeros": '''
def hysop_array_generated_method(shape, order=HYSOP_ORDER, **kargs):
    """
    Return a new array of given shape, filled with zeros of type HYSOP_{TYPE}.
    """
    dtype = HYSOP_{TYPE}
    return np.zeros(shape=shape, order=order, dtype=dtype, **kargs)
''',
        "{type}_full": '''
def hysop_array_generated_method(shape, fill_value, order=HYSOP_ORDER, **kargs):
    """
    Return a new array of given shape, filled with fill_value of type HYSOP_{TYPE}.
    """
    dtype = HYSOP_{TYPE}
    return np.full(shape=shape, fill_value=fill_value, order=order, dtype=dtype, **kargs)
''',
    }

    hysop_types = ["real", "complex", "integer", "index", "dim", "bool"]

    for ht in hysop_types:
        for _fname, fdefinition in functions.items():
            fname = _fname.format(type=ht, TYPE=ht.upper())
            fdef = """
import numpy as np
from hysop.constants import HYSOP_REAL, HYSOP_COMPLEX, HYSOP_ORDER
from hysop.constants import HYSOP_INTEGER, HYSOP_INDEX, HYSOP_DIM, HYSOP_BOOL
{}
""".format(
                fdefinition.format(type=ht, TYPE=ht.upper())
            )
            namespace = dict()
            exec(fdef, namespace)
            setattr(npw, fname, namespace["hysop_array_generated_method"])
            if ht == "integer":
                fname = _fname.format(type="int")
                setattr(npw, fname, namespace["hysop_array_generated_method"])


__generate_hysop_type_functions()


[docs] def ndindex_with_ghosts(shape, ghosts): check_instance(shape, tuple) check_instance(ghosts, (list, tuple, npw.ndarray)) if not isinstance(ghosts[0], (list, tuple, npw.ndarray)): ghosts = (ghosts,) for idx in npw.ndindex(*shape): ghosts_idx = tuple( tuple(i + g for (i, g) in zip(idx, ghost)) for ghost in ghosts ) yield (idx,) + ghosts_idx
[docs] def slices_empty(slices, shape): if not __debug__: return False if slices is Ellipsis: return False from hysop.core.arrays.array import Array if isinstance(slices, (int, npw.integer, npw.ndarray, Array)): return slices = (slices,) if isinstance(slices, slice) else slices assert len(shape) >= len(slices) shape = shape[: len(slices)] empty = tuple( slices[i].indices(shape[i]) for i in range(len(slices)) if isinstance(slices[i], slice) ) empty = tuple((i >= j) for (i, j, _), ss in zip(empty, shape)) return any(empty)
[docs] def set_readonly(*args): from hysop.testsenv import __HAS_OPENCL_BACKEND__ from hysop.core.arrays.all import Array if __HAS_OPENCL_BACKEND__: from hysop.core.arrays.all import OpenClArray for arg in args: if __HAS_OPENCL_BACKEND__ and isinstance(arg, OpenClArray): continue if isinstance(arg, Array): arg = arg.handle arg.setflags(write=False)
[docs] def fancy_print( a, replace_values={}, replace_views={}, element_width=6, inital_val=None, **print_opts, ): """ Print values with ghosts replaced by symbol. Mainly for debug purposes. Parameters ---------- a: np.ndarray Array to be printed. replace_values: dict, optional Replace value matching key predicate by value in array. Predicates take the array as parameter. Values can be any printable object. replace_views: dict, optional Replace each key view by value in array. Values can be any printable object. element_width: int, optional String width of the printed array values. inital_val: object, optional Initially fill the new array with given val. If specified, new array won't be initialized by input array. print_opts: Numpy printing options. Default options are: threshold = 10k linewidth = 1k nanstr = 'nan' infstr = 'inf' formatter = custom formatter """ check_instance(a, npw.ndarray) strarr = npw.empty_like(a, dtype=object) if inital_val is None: strarr[...] = a else: strarr[...] = inital_val for predicate, replace_val in replace_values.items(): assert callable(predicate) pred = predicate(a) strarr[pred] = replace_val for view, replace_val in replace_views.items(): strarr[view] = replace_val _formatter = { object: lambda x: "{:^{width}}".format(x, width=element_width)[:element_width], float: lambda x: "{:{width}.2f}".format(x, width=element_width), } _print_opts = dict( threshold=10000, linewidth=1000, nanstr="nan", infstr="inf", formatter={"object": lambda x: _formatter.get(type(x), _formatter[object])(x)}, ) _print_opts.update(print_opts) from hysop.tools.contexts import printoptions with printoptions(**_print_opts): print(strarr)
npw.set_readonly = set_readonly npw.ndindex_with_ghosts = ndindex_with_ghosts npw.fancy_print = fancy_print